﻿#pragma once
#include "common.h"

#include "MusicReader.h"

//#pragma warning(disable:4251)

// include OpenAL library
#include <AL/al.h>
#include <AL/alc.h>
#include <AL/alext.h>
#include <AL/efx.h>
#include <AL/efx-creative.h>
#include <AL/efx-presets.h>
//#include <alure.h> // OpenAL Soft library

// include OpenCV library
//#include <opencv2/core.hpp>

// include SoundTouch library
#include <SoundTouch.h>
#include <STTypes.h>
#include <FIFOSamplePipe.h>
#include <FIFOSampleBuffer.h>
#include <BPMDetect.h>

// Qt includes
#include <QObject>
//#include <QMetaObject>
#include <QDebug>
//#include <QSlider>

// Std includes
#include <iostream>
//#include <string>
#include <vector>
//#include <queue>
//#include <cmath>
#include <algorithm>
#include <chrono>
//#include <windows.h>
#include <thread>
#include <mutex>
//#include <future>

// define global variables
//static int		MAX_PER_CHANNEL_BUFFER_SIZE = 5000;
//static int		BIT_RATE = 128000; // 比特率
extern float	TEMPO;	  // 速度
extern float	PITCH;	  // 音调
extern float	RATE;	  // 音速率
extern int      al_get_error; // 用于保存 OpenAL 错误信息
extern bool     is_ALC_EXT_EFX_supported; // 判断是否支持 ALC_EXT_EFX

// 宏定义
#define NUM_BUFFERS 8 // OpenAL 缓冲区数量
//#define BUFFER_MILLISECONDS 500 // OpenAL 缓冲区时长
#define al_debug(str) if((al_get_error = alGetError()) != AL_NO_ERROR) { \
	qDebug() << str \
		<< "[OpenAL error]:" << "(" << al_get_error << ")" \
		<< alGetString(al_get_error); \
	__debugbreak(); \
	return; \
} // 输出 OpenAL 错误 str 信息并中断


// 模板函数，根据模板参数获取 OpenAL 格式
template<typename T>
ALenum get_openal_format(int channels);
template<>
ALenum get_openal_format<int16_t>(int c);
template<>
ALenum get_openal_format<float>(int c);

class MusicPlayer : public QObject
{
	Q_OBJECT

public:
	MusicPlayer() = default;
	MusicPlayer(const std::string& filename);
	~MusicPlayer();

	void init_player();
	const double get_reader_duration() const;
	void set_audio_tempo(float tempo);
	void set_audio_pitch(float pitch);
	void set_audio_rate(float rate);
	void set_volume(int volume);

	//void decode_thread_func();
	void queue_SoundTouch_convert_frame();
	
	void play();
	void pause();

	void reset_p_swr_context_SoundTouch(
		AVChannelLayout st_layout = AV_CHANNEL_LAYOUT_MONO,
		int st_sample_rate = 44100,
		AVSampleFormat st_sample_fmt = AV_SAMPLE_FMT_FLT);

	void reset_p_swr_context_output(
		AVChannelLayout out_layout = AV_CHANNEL_LAYOUT_MONO,
		int out_sample_rate = 44100,
		AVSampleFormat out_sample_fmt = AV_SAMPLE_FMT_S16);

	void set_listener_coordinate(float x = .0f,
		float y = .0f, float z = .0f);

	void seeking(int64_t pos_us);

	void seek_to_position(int64_t pos_us);

	//void skip_processed_buffers(ALuint source);

	//void next_audio_frame();

	MusicReader* my_ffmpeg; // 解码对象
	void resave();

	// SoundTouch 对象
	soundtouch::SoundTouch soundTouch;

	// OpenAL 混响效果指针
	LPALGENEFFECTS alGenEffects;
	LPALDELETEEFFECTS alDeleteEffects;
	LPALEFFECTI alEffecti;
	LPALEFFECTF alEffectf;
	LPALGENAUXILIARYEFFECTSLOTS alGenAuxiliaryEffectSlots;
	LPALDELETEAUXILIARYEFFECTSLOTS alDeleteAuxiliaryEffectSlots;
	LPALAUXILIARYEFFECTSLOTI alAuxiliaryEffectSloti;

	/*
	// Declare the function pointer for alGenFilters
	typedef void (AL_APIENTRY* LPALGENFILTERS)(ALsizei, ALuint*);
	LPALGENFILTERS alGenFilters;
	LPALDELETEFILTERS alDeleteFilters;
	// Declare the function pointer for alFilterf
	typedef void (AL_APIENTRY* LPALFILTERF)(ALuint, ALenum, ALfloat);
	LPALFILTERF alFilterf;
	// Declare the function pointer for alFilteri
	typedef void (AL_APIENTRY* LPALFILTERI)(ALuint, ALenum, ALint);
	LPALFILTERI alFilteri;
	*/

	// OpenAL 更新效果参数
	template <typename T>
	void update_affects(T* obj, void (T::* func)(float), float value);

	void set_density(float density);
	void set_diffusion(float diffusion);
	void set_gain(float gain);
	void set_decay_time(float decay_time);
	void set_gainhf(float gainhf);
	void set_decay_hfratio(float decay_hfratio);
	void set_reflections_gain(float reflections_gain);
	void set_reflections_delay(float reflections_delay);
	void set_late_reverb_gain(float late_reverb_gain);

	// OpenAL 播放状态
	bool					is_playing;


signals:
	void audio_frame_read(int64_t position); // 读取到帧信号
	void audio_end(); // 音频播放结束信号
	void audio_error(const std::string& error_msg); // 错误信号
	void open_file_failed(const std::string& error_msg); // 打开文件失败信号

private:
	//void init_PortAudio();
	void init_OpenAL();
	void create_OpenAL_effect();
	void initialize_listener();
	void init_set_OpenAL();
	void init_SoundTouch();

	void play_thread_func();
	void queue_audio_frame_to_OpenAL(AVFrame*& al_queue_frame);
	void process_playback_OpenAL();
	void clear_OpenAL_buffers();

	// OpenAL 变量
	//std::promise<AVFrame*>	ffmpeg_promise;
	//std::condition_variable	ffmpeg_cv;

	bool					is_seeking;
	std::vector<AVFrame*>	frame_list; // 音频帧队列
	std::mutex				player_mutex; // frame_list 线程锁
	std::thread				decode_thread;
	std::thread				play_thread;
	ALCdevice*				al_device = nullptr;
	ALCcontext*				al_context = nullptr;
	ALuint					al_source = 0;
	ALuint					al_buffers[NUM_BUFFERS];
	ALuint					al_reverb_effect = 0;
	ALuint					al_aux_effect_slot = 0; // 效果槽 ID
	ALuint al_lowpass_filter = 0; // 低通滤波器
	ALuint al_highpass_filter = 0; // 高通滤波器
	//ALuint al_echo_effect_slot; // 回声效果槽 ID
};

